<?php

declare(strict_types=1);

namespace app\common\repository\user;

use app\common\exception\AdminException;
use app\common\model\user\User;
use app\common\repository\BaseRepository;
use app\common\repository\UserPreferenceRepository;
use think\db\exception\DbException;

class UserRepository extends BaseRepository
{
    protected \app\common\model\BaseModel $model;

    public function __construct(User $model)
    {
        $this->model = $model;
    }

    /**
     * 获取用户列表（带经纬度距离过滤）
     *
     * @param string $user_id
     * @param array $where
     * @param int $page
     * @param int $pageSize
     * @return array
     * @throws DbException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getUserList(string $user_id, array $where = [], int $page = 1, int $pageSize = 15): array
    {
        $currentUser = $this->model->find($user_id);

        $userPreference = app()->make(UserPreferenceRepository::class);
        $dislikeUserIds = $userPreference->getColumn('target_user_id', [
            'user_id' => $user_id,
        ]);

        // 参数校验
        $lng = $where['lng'] ?? null;
        $lat = $where['lat'] ?? null;
        if (empty($lng) || empty($lat)) {
            throw new \InvalidArgumentException("经纬度参数不能为空");
        }
        if (!is_numeric($lng) || !is_numeric($lat)) {
            throw new \InvalidArgumentException("经纬度参数必须为数字");
        }
        $lat = (float)$lat;
        $lng = (float)$lng;
        if ($lat < -90 || $lat > 90 || $lng < -180 || $lng > 180) {
            throw new \InvalidArgumentException("经纬度超出有效范围");
        }

        $sex = $where['sex'];
        $minAge = $where['min_age'] ?? 18;
        $maxAge = $where['max_age'] ?? 60;
        $maxDistance = $where['km'] ?? null;
        if ($maxDistance !== null && (!is_numeric($maxDistance) || $maxDistance <= 0)) {
            throw new \InvalidArgumentException("距离范围必须为正数");
        }

        // 分页参数校验
        $page = max(1, (int)$page);
        $pageSize = max(1, (int)$pageSize);
        $pageSize = min($pageSize, 100); // 限制每页最多100条

        // 初始化查询
        $query = $this->model->query();

        // 年龄条件
        if ($minAge > 0 || $maxAge < 100) {
            $query->whereBetween('age', [$minAge, $maxAge]);
        }

        // 性别条件
        if(isset($sex) && $sex !== 2) {
            $query->where('sex', $sex);
        }

        // 排除不喜欢的人
        if(!empty($dislikeUserIds)) {
            $query->whereNotIn('id', $dislikeUserIds)->where('id', '<>', $user_id);
        }

        // 距离条件
        if ($maxDistance) {
            $distanceSql = "ST_Distance_Sphere(POINT({$lng}, {$lat}), POINT(lng, lat))";
            $query->field([
                '*',
                "{$distanceSql} AS distance"
            ])->whereRaw(
                "{$distanceSql} <= ?", [$maxDistance * 1000] // 转换为米
            )->order('distance', 'asc');
        }

        $query->hidden(['phone', 'id_card', 'password', 'create_time', 'update_time', 'delete_time']);

        try {
            $paginator = $query->paginate([
                'page' => $page,
                'list_rows' => $pageSize,
            ]);
        } catch (DbException $e) {
            throw new AdminException('查询失败，请重试！'.$e->getMessage());
        }

        $candidates = $paginator->items();
        // 计算每个候选人的匹配度分数
        foreach ($candidates as &$candidate) {
            $candidate['score'] = $this->calculateMatchScore($currentUser, $candidate);
        }
        // 根据分数排序
        usort($candidates, function ($a, $b) {
            return $b['score'] <=> $a['score'];
        });

        return [
            'total' => $paginator->total(),
            'list'  => $candidates,
        ];
    }

    /**
     * 计算匹配度分数
     *
     */
    private function calculateMatchScore($userA, $userB)
    {
        $score = 0;

        // 年龄差异
        $ageDifference = abs($userA['age'] - $userB['age']);
        $score += max(0, 100 - $ageDifference);

        // 性别偏好
//        if ($userA['sex'] === $userB['sex']) {
//            $score += 50;
//        }
//        if ($userB['sex'] === $userA['sex']) {
//            $score += 50;
//        }

        // 兴趣相似度
        $commonInterests = array_intersect($userA['interests'], $userB['interests']);
        $score += count($commonInterests) * 10;

        // 距离（假设已经在查询中处理了距离过滤）
        return $score;
    }
}